/*   Copyright (C) 2011 Wolfgang Hankeln, Norma J. Wendel
 *
 *   This file is part of CDinFusion.
 *
 *   CDinFusion is free software: you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public 
 *   License in version 3 (LGPL3) as published by the Free Software
 *   Foundation version 3 of the License.
 *
 *   CDinFusion is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the Lesser General Public
 *   License along with CDinFusion; see the file COPYING. If not,
 *   write to the Free Software Foundation, 59 Temple Place - Suite 330,
 *   Boston, MA 02111-1307, USA or see <http://www.gnu.org/licenses/>.
 *   
 *   If you have any questions, send an email to: megx@mpi-bremen.de.
 */
package org.cdinfusion.data;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class CDValidator {
	
	public boolean isNotASCII(String teststring){
		    return teststring.contains("&#");
	}
	
	public String correctValueOfLatLon(String latlon) throws Exception{
		boolean b_lat = latlon.matches("((^" +
				"((90((\\.|\\,)0{1,5})?\\s?[NSns\\-\\+])|([0-8]?\\d((\\.|\\,)\\d{1,5})?\\s?[NSns\\-\\+])" +
				"|([NSns\\-\\+]\\s?90((\\.|\\,)0{1,5})?)|([NSns\\-\\+]\\s?[0-8]?\\d((\\.|\\,)\\d{1,5})?))" +
				"\\s{1,}"+
				"((180((\\.|\\,)0{1,5})?\\s?[EWew\\-\\+])|((([01][0-7]\\d)|0?\\d{1,2})((\\.|\\,)\\d{0,5})?\\s?[EWew\\-\\+])" +
				"|([EWew\\-\\+]\\s?180((\\.|\\,)0{1,5})?)|([EWew\\-\\+]\\s?(([01][0-7]\\d)|0?\\d{1,2})((\\.|\\,)\\d{0,5})?))$)" +
				"|(^$))");
		if(b_lat == false) {
			System.out.println("lat lon ("+latlon+") false! Exception will be thrown!");
			Exception e = new Exception("latitude/longitude have the value "+latlon+", that is not correct! (e.g. 23.56734 N 258.42561 S)");
			throw(e);
		}
		String lat_lon = "";
		if(!latlon.equals("") & b_lat == true){
			String lat = "";
			String lon = "";
			String help_one = "";
			String help_two = "";
			ArrayList<Integer> where = new ArrayList<Integer>(); 
			int amount = 0;
			latlon = latlon.toUpperCase().trim().replaceAll("\\s{2,}", " ");
			char[] array = latlon.toCharArray();
			
			for(int i = 0; i < array.length; i++){
				if(array[i] == ' '){
					amount++;
					where.add(i);
				}
			}

			if(amount == 1){
				lat = latlon.substring(0, where.get(0));
				lon = latlon.substring(where.get(0));
			}else{
				if(amount == 3){
					lat = latlon.substring(0, where.get(1));
					lon = latlon.substring(where.get(1));
				}else{
					if(amount == 2){
						lat = latlon.substring(0, where.get(0));
						lon = latlon.substring(where.get(0));
						if(!lat.contains("N")&!lat.contains("S")&!lat.contains("+")&!lat.contains("-")){
							lat = latlon.substring(0, where.get(1));
							lon = latlon.substring(where.get(1)); 
						}
						
					}
				}
			}
			lat = lat.trim();
			lon = lon.trim();
			lat = lat.replace("+", "N");
			lat = lat.replace("-", "S");
			if(lat.startsWith("N")|lat.startsWith("S")){
				help_one = lat.substring(0, 1);
				help_two = lat.substring(1);
				lat = help_two.trim() + " " + help_one.trim();
			}else{
				help_one = lat.substring(lat.length()-1);
				help_two = lat.substring(0, lat.length()-1);
				lat = help_two.trim() + " " + help_one.trim();
			}
			lon = lon.replace("+", "E");
			lon = lon.replace("-", "W");
			if(lon.startsWith("W")|lon.startsWith("E")){
				help_one = lon.substring(0, 1);
				help_two = lon.substring(1);
				lon = help_two.trim() + " " + help_one.trim();
			}else{
				help_one = lon.substring(lon.length()-1);
				help_two = lon.substring(0, lon.length()-1);
				lon = help_two.trim() + " " + help_one.trim();
			}
			
			lat_lon = lat +" "+ lon;
		}
		return (lat_lon);
	}

	public String correctValueOfPrimer(String primer) throws Exception{
		boolean b_primer = primer.toLowerCase().matches("(^(fwd:)?[a-z]+\\s(rev:)?[a-z]+$)|(^$)");
		if(b_primer == false){
			System.out.println("pcr_primers false! Exception will be thrown!");
			Exception e = new Exception("The pcr primers ("+primer+") are incorrect! The sequences are required (e.g. FWD:{dna} REV:{dna}).");
			throw(e);
		}
		int i = 0;
		if(primer.toLowerCase().matches("(^[a-z]+\\s[a-z]+$)") == true){
			i = primer.indexOf(" ");
			primer = "FWD:" + primer.substring(0, i) + " REV:" +primer.substring(i+1);
		}
		return(primer);
	}
	
	public void correctValueOfIntegerFields(String value) throws Exception{
		boolean b_value = value.matches("(^[0-9]{0,}$)|(^$)");
		if(b_value == false){
			System.out.println("value of int: false! Exception will be thrown!");
			Exception e = new Exception("The value ("+value+") of an integer field is incorrect!");
			throw(e);
		}
	}
	
	public void correctValueOfDateAndTime(String date) throws Exception{
		boolean b_date = date.matches("(^\\d{4}(\\-(0\\d|1[012])(\\-(0\\d|[12]\\d|3[01])(.([01]?\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?([\\+\\-]\\d{2}:\\d{2})?)?)?)?$)|(^$)");
		if(b_date == false){
			System.out.println("date false! Exception will be thrown!");
			Exception e = new Exception("The collection date ("+date+") is incorrect! (e.g. yyyy-mm-dd");
			throw(e);
		}
	}

	public void useOfNonAsciiStudy(Object study) throws Exception{
		System.out.println("useOfNonAsciiStudy validation");
		String[] methods = this.getStudyGetters(study);
		for(int i = 0; i < methods.length; i++){
			if( isNotASCII(study.getClass().getMethod(methods[i], (Class[])null).invoke(study, (Object[])null).toString())){
				System.out.println("study: "+study.getClass().getMethod(methods[i], (Class[])null).invoke(study, (Object[])null).toString());
				Exception e = new Exception(" You used non ascii characters here: <b>"
						+study.getClass().getMethod(methods[i], (Class[])null).invoke(study, (Object[])null).toString()
						+ "</b>. Please go back and replace these with ascii characters. Sequin does not allow non ascii characters.</ br></ br>" +
						"Combinations of these characters are allowed:<b> !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~</b>!");
				throw(e);
			}
		}
	}
	
	public void useOfNonAsciiEnv(Object env) throws Exception{
		String[] methods = this.getEnvGetters(env);
		for(int i = 0; i < methods.length; i++){
			if( isNotASCII(env.getClass().getMethod(methods[i], (Class[])null).invoke(env, (Object[])null).toString())){
				System.out.println("env: "+env.getClass().getMethod(methods[i], (Class[])null).invoke(env, (Object[])null).toString());
				System.out.println("Using non ascii characters!");
				Exception e = new Exception(" You used non ascii characters here: <b>"
						+env.getClass().getMethod(methods[i], (Class[])null).invoke(env, (Object[])null).toString()
						+ "</b>. Please go back and replace these with ascii characters. Sequin does not allow non ascii characters.</ br></ br>" +
						"Combinations of these characters are allowed:<b> !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~</b>!");
				throw(e);
			}
		}
	}
	
	public void useOfNonAsciiFH(Object fh) throws Exception{
		String[] methods = this.getFHGetters(fh);
		for(int i = 0; i < methods.length; i++){
			if( isNotASCII(fh.getClass().getMethod(methods[i], (Class[])null).invoke(fh, (Object[])null).toString())){
				System.out.println("fh: "+fh.getClass().getMethod(methods[i], (Class[])null).invoke(fh, (Object[])null).toString());
				System.out.println("Using non ascii characters!");
				Exception e = new Exception(" You used non ascii characters here: <b>"
						+fh.getClass().getMethod(methods[i], (Class[])null).invoke(fh, (Object[])null).toString()
						+ "</b>. Please go back and replace these with ascii characters. Sequin does not allow non ascii characters.</ br></ br>" +
						"Combinations of these characters are allowed:<b> !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~</b>!");
				throw(e);
			}
		}
	}
	
	public String[] getStudyGetters(Object study){
		String[] methods;
		Method[] meth_all = study.getClass().getDeclaredMethods();
		
		List<String> find = new ArrayList<String>();
		
		int f = 0;
		String find_get = "";
		for(int d = 0; d < meth_all.length; d++){
				find_get = meth_all[d].toString();
				if(find_get.contains(".get")){
					find.add(find_get);
					f++;
				}
			}
		methods = new String[f];
			for(int c = 0; c < f; c++){
				methods[c] = find.get(c).toString();
		}
			for(int i = 0; i < methods.length; i++){
				methods[i] = methods[i].replaceAll("public java.lang.String org.cdinfusion.data.studytype.[A-Z_]{2,10}.", "");
				methods[i] = methods[i].replaceAll("public int org.cdinfusion.data.studytype.[A-Z_]{2,10}.", "");
				methods[i] = methods[i].substring(0, methods[i].length() - 2);
			}
		return(methods);
	}

	public String[] getEnvGetters(Object env){
		String[] methods;
		Method[] meth_all = env.getClass().getDeclaredMethods();
		
		List<String> find = new ArrayList<String>();
		
		int f = 0;
		String find_get = "";
		for(int d = 0; d < meth_all.length; d++){
				find_get = meth_all[d].toString();
				if(find_get.contains(".get")){
					find.add(find_get);
					f++;
				}
			}
		methods = new String[f];
			for(int c = 0; c < f; c++){
				methods[c] = find.get(c).toString();
		}
			for(int i = 0; i < methods.length; i++){
				methods[i] = methods[i].replaceAll("public java.lang.String org.cdinfusion.data.environment.[A-Za-z_]{2,17}.", "");
				methods[i] = methods[i].substring(0, methods[i].length() - 2);
			}
		return(methods);
	}
	
	public String[] getFHGetters(Object cdfh){
		String[] methods;
		Method[] meth_all = cdfh.getClass().getDeclaredMethods();
		
		List<String> find = new ArrayList<String>();
		
		int f = 0;
		String find_get = "";
		for(int d = 0; d < meth_all.length; d++){
			find_get = meth_all[d].toString();
			if(find_get.contains(".get")){
				find.add(find_get);
				f++;
			}
		}
		methods = new String[f];
		for(int c = 0; c < f; c++){
			methods[c] = find.get(c).toString();
		}
		for(int i = 0; i < methods.length; i++){
			methods[i] = methods[i].replaceAll("public java.lang.String org.cdinfusion.data.CDFastaHeader.", "");
			methods[i] = methods[i].substring(0, methods[i].length() - 2);
		}
		return(methods);
	}
}